#ifndef HTTPREQUEST_HPP_
#define HTTPREQUEST_HPP_

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/algorithm/string/join.hpp>
#include <curl/curl.h>

#pragma comment(lib, "libcurl")

using std::string;
using std::map;
using std::vector;
using std::advance;
using boost::algorithm::join;

typedef int (*PROGRESS_CALLBACK)(void* param, double downTotal, double downProgress, double upTotal, double upProgress);

typedef vector<unsigned char> HTTPREQUEST_DATA;
typedef map<string, string> HTTPREQUEST_POST;

class HTTPRequest
{
private:
  CURL* m_curl;
  curl_slist* m_header;
  
  struct ReadDataIterators {
    vector<unsigned char>::iterator m_current;
    vector<unsigned char>::iterator m_end;
  };

public:
  HTTPRequest();
  ~HTTPRequest();

  bool Initialized();

  void Get(string url, HTTPREQUEST_DATA* buffer, HTTPREQUEST_DATA* header);
  void Post(string url, HTTPREQUEST_POST& data, HTTPREQUEST_DATA* buffer, HTTPREQUEST_DATA* header);
  void Post(string url, HTTPREQUEST_DATA& data, HTTPREQUEST_DATA* buffer, HTTPREQUEST_DATA* header);
  
  void SetProgressCallback(PROGRESS_CALLBACK callback);

  void AddHeader(string pair);
  void ClearHeaders();

  void SetTimeout(int timeout);

  // due to the nature of curl_global_init this function is not thread-safe
  static bool GlobalInitialize();

  string Escape(string text);
  
protected:
  static size_t WriteCallback(void* data, size_t size, size_t members, HTTPREQUEST_DATA* buffer);
  static size_t ReadCallback(void* data, size_t size, size_t members, ReadDataIterators* iterators);
  static size_t HeaderCallback(void* data, size_t size, size_t members, HTTPREQUEST_DATA* buffer);

  void Send(string url, HTTPREQUEST_DATA* buffer, HTTPREQUEST_DATA* header);
};

#endif // HTTPREQUEST_HPP_